package com.chinawayltd.ews.sample.taskDispatch;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 订单仓库，负责源源不断在不同站点的订单架上取出最早需要运输的订单信息
 * @program: greeProject.timingTaskCenter
 * @description:
 * @author: xiazj
 * @create: 2018-07-12 18:53
 **/
public class OrderDepot {

    //匿名Comparator实现
    private static final Comparator<JSONObject> starttimeComparator = (JSONObject o1 , JSONObject o2) ->
            o1.getDouble(TaskDispatchConstants.TASKLIST_STARTTIME).compareTo(o2.getDouble(TaskDispatchConstants.TASKLIST_STARTTIME));

    private static Map<String, Queue<JSONObject>> classifiedOrders(JSONArray orders){
        if(orders == null || orders.isEmpty())throw new RuntimeException("orders must be not null and not empty!");

        Map<String, Queue<JSONObject>> result = new HashMap<>();
        for (int i = 0; i < orders.size(); i++) {
            JSONObject order  = orders.getJSONObject(i);
            String pickup = order.getString(TaskDispatchConstants.TASKLIST_PICKUP);

            if(StringUtils.isBlank(pickup)){
                throw new RuntimeException("pickup is null or empty in order:【" + order.toString() + "】");
            }

            Queue<JSONObject> rackOrders = result.get(pickup);
            if(rackOrders == null){
                rackOrders = new PriorityQueue<>(starttimeComparator);
                result.put(pickup, rackOrders);
            }
            rackOrders.offer(order);
        }

        return result;
    }

    public static OrderDepot initialize(JSONArray orders){
        return new OrderDepot(classifiedOrders(orders));
    }

    /**
     * 当前订单仓库需要取货的订单架名称
     * */
    private String currentRackKey;

    /**
     * 当前订单仓库订单架的名称列表
     * */
    private List<String> rackKeyList;

    /**
     * 当前订单仓库订单架的集合
     * */
    private Map<String, Queue<JSONObject>> rackMap;

    private OrderDepot(Map<String, Queue<JSONObject>> rackMap) {
        this.rackMap = rackMap;
    }

    /**
     * 从订单仓库的所有订单架上筛选出当前最早需要运输的订单信息
     * @return 最早需要运输的订单信息
     */
    public JSONObject extractEarliestOrder(){
        this.rackKeyList = new ArrayList<>();
        JSONObject earliestOrder = null;

        List<JSONObject> rackFristOrders = new ArrayList<>();
        //从所有订单架子上取出各自订单架最早需要送达的订单
        for (String rackKey : rackMap.keySet()) {
            Queue<JSONObject> rackQueue = rackMap.get(rackKey);
            JSONObject order = rackQueue.poll();
            if(order != null)rackFristOrders.add(order);
        }

        if(!rackFristOrders.isEmpty()){
            //根据订单最早送货时间排序
            rackFristOrders.sort((Object o1, Object o2) ->{
                JSONObject obj1 = (JSONObject)o1;
                JSONObject obj2 = (JSONObject)o2;
                Double startTime1 = obj1.getDouble(TaskDispatchConstants.TASKLIST_STARTTIME);
                Double startTime2 = obj2.getDouble(TaskDispatchConstants.TASKLIST_STARTTIME);
                if(startTime1 != null && startTime2 != null){
                    return startTime1.compareTo(startTime2);
                }
                return 0;
            });

            //把订单架上所有最早送的订单集合中最早的那订单返回出去，并根据订单架上最早的订单重新排列订单架的取货顺序
            for (int i = 0; i < rackFristOrders.size(); i++) {
                JSONObject order = rackFristOrders.get(i);
                String pickup = order.getString(TaskDispatchConstants.TASKLIST_PICKUP);
                rackKeyList.add(pickup);
                if(i == 0){
                    earliestOrder = order;
                }else{
                    returnOrderInRack(order);
                }
            }
        }

        return earliestOrder;
    }

    /**
     * 从订单仓库中取出当前最早需要运输的订单信息
     * @return 最早需要运输的订单信息
     */
    public JSONObject extractOrder(){
        /**
         * 如果当前订单仓库中最早需要运输的仓库订单架的编号为空，
         * 证明订单仓库需要把第一个订单架的编号为当前最早需要运输的仓库订单架的编号
         * */
        if(currentRackKey == null){
            currentRackKey = rackKeyList.get(0);
        }

        JSONObject earliestOrder = getNextOrder();
        return earliestOrder;
    }

    /**
     * 把当前订单退还到所属的订单架上
     * @param order
     */
    private void returnOrderInRack(JSONObject order){
        String pickup = order.getString(TaskDispatchConstants.TASKLIST_PICKUP);
        rackMap.get(pickup).offer(order);
    }

    /**
     * 退还当前不合适的订单让订单回到自己订单架上，
     * 并从下一个订单架上取出第一个订单返回
     * @param order
     * @return
     */
    public JSONObject returnOrderAndExtractNextRackOrder(JSONObject order){
        returnOrderInRack(order);

        JSONObject earliestOrder = null;

        //取出下一个订单架名称，如果下一个订单架为空则证明订单仓库已经没有合适的订单返回
        currentRackKey = getNextRackKey();
        if(currentRackKey != null){
            earliestOrder = getNextOrder();
        }

        return earliestOrder;
    }

    /**
     * 寻找当前订单仓库最早需要被运输的订单信息，
     * 如果取到订单则不继续寻找，但如果某一个订单架已经被取空
     * 则自动找下一个订单架里面的订单信息，直到所有订单架都取不出订单为止
     **/
    private JSONObject getNextOrder(){
        JSONObject earliestOrder = null;
        while (earliestOrder == null){
            Queue<JSONObject> currentRack = rackMap.get(currentRackKey);
            earliestOrder = currentRack.poll();
            if(earliestOrder != null){
                break;
            }

            currentRackKey = getNextRackKey();
            if(currentRackKey == null)break;
        }
        return earliestOrder;
    }

    /**
     * 根据当前订单架来寻找下一个订单架名称
     * @return
     */
    private String getNextRackKey(){
        String nextRackKey = null;
        int nextRackKeyIdx = rackKeyList.indexOf(currentRackKey) + 1;
        if(nextRackKeyIdx < rackKeyList.size()){
            nextRackKey = rackKeyList.get(nextRackKeyIdx);
        }
        return nextRackKey;
    }

}
